from baseview import BaseView
from Bases import BaseObject
from ..bases import widgets
from ..bases.propertylist import PropertyListModel
from ..editors import EditorBase
from .. import osc_tree

class CommSetupView(BaseView):
    topwidget_name = 'Communication Setup'
    topwidget_cls = widgets.Notebook
    _Properties = {'session_name':dict(type=str)}
    def __init__(self, **kwargs):
        #self.topwidget = widgets.VBox()
        super(CommSetupView, self).__init__(**kwargs)
        
        self.session_name = self.GLOBAL_CONFIG.get('session_name')
        self.bind(session_name=self._on_session_name_set)
        self.GLOBAL_CONFIG.bind(update=self.on_GLOBAL_CONFIG_update)
        self.comm = self.MainController.comm
        
        vbox = widgets.VBox()
        self.txtSessionName = widgets.Entry(name='Session Name', Property=(self, 'session_name'))
        vbox.pack_start(self.txtSessionName.topwidget)
        
        self.session_discovery = SessionDiscovery(MainController=self.MainController)
        vbox.pack_start(self.session_discovery.topwidget, expand=True)
        
        self.topcontainer.add_page(label='Session', widget=vbox)
        
        self.OSCSetup = OSCSetup(MainController=self.MainController)
        self.topcontainer.add_page(label='OSC', widget=self.OSCSetup.topwidget)
        self.DMXSetup = DMXSetup(MainController=self.MainController)
        self.topcontainer.add_page(label='DMX', widget=self.DMXSetup.topwidget)
        self.MidiSetup = MidiSetup(MainController=self.MainController)
        self.topcontainer.add_page(label='MIDI', widget=self.MidiSetup.topwidget)
        
        self.topwidget.show_all()
        
    def unlink(self):
        super(CommSetupView, self).unlink()
        self.GLOBAL_CONFIG.unbind(self)
        
    def _on_session_name_set(self, **kwargs):
        value = kwargs.get('value')
        if value == '':
            value = None
        if value != self.GLOBAL_CONFIG.get('session_name'):
            self.GLOBAL_CONFIG['session_name'] = value
            
    def on_GLOBAL_CONFIG_update(self, **kwargs):
        value = self.GLOBAL_CONFIG.get('session_name')
        if value is None:
            value = ''
        if value != self.session_name:
            self.session_name = value
        
class SessionDiscovery(EditorBase):
    topwidget_label = 'Discovered Sessions'
    def init_editor(self, **kwargs):
        self.osc_io = self.MainController.comm.osc_io
        self.list = widgets.TreeList(name='', list_types=[str, str], column_names=['id', 'Name'], column_order=[1])
        self.update_list()
        self.topwidget.pack_start(self.list.topwidget, expand=True)
        self.osc_io.bind(discovered_sessions=self.on_discovered_sessions_update)
        
    def unlink(self):
        super(SessionDiscovery, self).unlink()
        self.osc_io.unbind(self)
        
    def update_list(self):
        self.list.clear()
        for session in self.osc_io.discovered_sessions:
            self.list.update({session:session})
        
    def on_discovered_sessions_update(self, **kwargs):
        self.update_list()

class OSCSetup(EditorBase):
    topwidget_label = 'OSC Setup'
    def init_editor(self, **kwargs):
        self.osc_io = self.MainController.comm.osc_io
        self.sb_master_priority = widgets.SpinBtn(label='Master Priority', Property=(self.osc_io, 'master_priority'))
        self.topwidget.pack_start(self.sb_master_priority.topwidget)
        self.notebook = widgets.Notebook()
        c = self.make_child_editor(OSCClient, 'clients')
        self.notebook.add_page(label='Client List', widget=c.topwidget)
        t = self.make_child_editor(OSCNodeTree, 'nodes')
        self.notebook.add_page(label='Node Tree', widget=t.topwidget)
        
        self.topwidget.pack_start(self.notebook, expand=True)
        
    def unlink(self):
        super(OSCSetup, self).unlink()
        self.sb_master_priority.unlink()
        
class OSCClient(EditorBase):
    topwidget_label = 'Clients'
    def init_editor(self, **kwargs):
        self.osc_io = self.MainController.comm.osc_io
        types = [str, str, str, int, int, bool, bool, bool, bool, bool, bool, bool, bool]
        self.col_names = ['Name', 'Session', 'Address', 'Port', 'Priority', 'Master', 'm_active', 'Slave', 's_active', 'Local', 'l_active', 'SameSession', 'ss_active']
        self.col_attr_map = {'Name':'name', 'Session':'session_name', 'Address':'address', 'Port':'port', 'Priority':'master_priority', 
                             'Master':'isMaster', 'Slave':'isSlave', 'Local':'isLocalhost', 'SameSession':'isSameSession'}
        order = [0, 1, 2, 3, 4, 5, 7, 9, 11]
        self.client_list = widgets.TreeList(name='', list_types=types, column_names=self.col_names, column_order=order)
        self.update_client_list()
        self.topwidget.pack_start(self.client_list.topwidget, expand=True)
        
        self.osc_io.bind(client_added=self.on_client_added, 
                         client_removed=self.on_client_removed)
        
    def unlink(self):
        super(OSCClient, self).unlink()
        self.osc_io.unbind(self)
        for c in self.osc_io.clients.itervalues():
            c.unbind(self)
        
    def update_client_list(self, key=None):
        if key:
            clients = {key:self.osc_io.clients[key]}
        else:
            clients = self.osc_io.clients
        for key, val in clients.iteritems():
            if True:#not val.isLocalhost:
                row = []
                for i, name in enumerate(self.col_names):
                    if 'active' in name:
                        value = True
                    else:
                        value = getattr(val, self.col_attr_map[name])
                        if value is None:
                            value = self.client_list.list_types[i]()
                    row.append(value)
                self.client_list.update({key:row[1:]})
                val.bind(property_changed=self.on_client_property_changed)
        
    def on_client_added(self, **kwargs):
        name = kwargs.get('name')
        self.update_client_list(name)
        
    def on_client_removed(self, **kwargs):
        self.client_list.clear()
        self.update_client_list()
    
    def on_client_property_changed(self, **kwargs):
        client = kwargs.get('obj')
        self.update_client_list(client.name)
        
class OSCNodeTree(EditorBase):
    topwidget_label = 'OSC Node Tree'
    def init_editor(self, **kwargs):
        self.node_tree = osc_tree.OSCTree(root_node=self.MainController.comm.osc_io.osc_tree)
        self.topwidget.pack_start(self.node_tree.topwidget, expand=True)
    def unlink(self):
        self.node_tree.unlink()
        super(OSCNodeTree, self).unlink()
        
class DMXSetup(EditorBase):
    topwidget_label = 'DMX Setup'
    def init_editor(self, **kwargs):
        self.comm = self.MainController.comm
        self.io_editor = None
        
        types = [str, str, bool, bool]
        names = ['id', 'Name', 'Active', 'cell_active']
        order = [1, 2]
        self.io_list = widgets.TreeList(name='', list_types=types, 
                                           column_names=names, column_order=order)
        self.update_io_list()
        self.io_list.connect('selection_changed', self.on_io_list_selection_changed)
        self.io_list.connect('cell_toggled', self.on_io_list_cell_toggled)
        self.topwidget.pack_start(self.io_list.topwidget, expand=True)
        
        self.comm.connect('io_update', self.on_comm_io_update)
        
    def unlink(self):
        super(DMXSetup, self).unlink()
        self.comm.disconnect(callback=self.on_comm_io_update)
        
    def build_io_editor(self, **kwargs):
        obj = kwargs.get('obj')
        if self.io_editor:
            self.io_editor.unlink()
            topw = self.io_editor.topwidget
            parent = topw.get_parent()
            if parent:
                parent.remove(topw)
        if obj is not None:
            self.io_editor = self.make_child_editor(DMXIOEditor, 'io_editor', **kwargs)
            self.topwidget.pack_start(self.io_editor.topwidget, expand=True)
            
    def update_io_list(self, key=None):
        if key:
            cls = self.comm.io_classes[key]
            self.io_list.update({key:[cls.ui_name, key in self.comm.dmx_io, True]})
        else:
            for key, cls in self.comm.io_classes.iteritems():
                self.io_list.update({key:[cls.ui_name, key in self.comm.dmx_io, True]})
                
            
    def on_io_list_selection_changed(self, **kwargs):
        key = kwargs.get('key')
        self.build_io_editor(obj=self.comm.dmx_io.get(key))
        
    def on_io_list_cell_toggled(self, **kwargs):
        key = kwargs.get('key')
        state = kwargs.get('state')
        if state:
            self.comm.build_io(key)
        else:
            self.comm.remove_io(key)
            
    def on_comm_io_update(self, **kwargs):
        key = kwargs.get('key')
        if key not in self.comm.dmx_io:
            key = None
        self.update_io_list(key)
        
class DMXIOEditor(EditorBase):
    topwidget_label = ''
    def init_editor(self, **kwargs):
        self.obj = kwargs.get('obj')
        self.SettingsPropWidgets = {}
        if self.obj.ui_name == 'Artnet':
            ed = self.make_child_editor(ArtnetEditor, 'artnet_editor', manager=self.obj)
            self.topwidget.pack_start(ed.topwidget, expand=True)
        else:
            vbox = widgets.VBox()
            for key, prop in self.obj.SettingsProperties.iteritems():
                if prop.type == int:
                    cls = widgets.SpinBtn
                elif prop.type == str:
                    cls = widgets.Entry
                else:
                    continue
                frm = widgets.Frame(label=' '.join(key.split('_')).title())
                w = cls(no_frame=True, Property=prop)
                self.SettingsPropWidgets[key] = w
                frm.pack_start(w.topwidget, expand=True)
                vbox.pack_start(frm, expand=True)
            self.topwidget.pack_start(vbox, expand=True)
        #self.topwidget = widgets.Frame(label=self.obj.ui_name)
        
        self.btn_connect = widgets.ToggleBtn(label='Connect', Property=(self.obj, 'connected'))
        #self.btn_connect.connect('clicked', self.on_btn_connect_clicked)
        self.topwidget.pack_start(self.btn_connect.widget)
        
        #self.obj.connect('state_changed', self.btn_connect.on_object_value_changed)
        
    def unlink(self):
        for w in self.SettingsPropWidgets.itervalues():
            w.unlink()
        self.btn_connect.unlink()
        super(DMXIOEditor, self).unlink()
    
class ArtnetEditor(EditorBase):
    topwidget_label = ''
    def init_editor(self, **kwargs):
        self.manager = kwargs.get('manager')
        self.col_names = ['id', 'LongName', 'IPAddress', 'Port', 'style', 'InputPorts', 'OutputPorts', 'last_update']
        types = [str]*len(self.col_names)
        types[0] = int
        self.node_list = widgets.TreeList(name='Nodes', column_names=self.col_names, list_types=types, column_order=range(len(self.col_names))[1:])
        self.update_node_list()
        self.topwidget.pack_start(self.node_list.topwidget, expand=True)
        self.manager.bind(new_node=self.on_new_node, del_node=self.on_del_node)
        
    def update_node_list(self, key=None):
        if key is not None:
            for nodes in self.manager.Nodes.itervalues():
                node = nodes.get(key)
                if node:
                    break
            nodedict = {key:node}
        else:
            self.node_list.clear()
            nodelist = []
            for nodes in self.manager.Nodes.itervalues():
                nodelist.extend(nodes.values())
            nodedict = dict(zip([n.id for n in nodelist], nodelist))
        for nid, node in nodedict.iteritems():
            l = []
            for attr in self.col_names:
                l.append(str(getattr(node, attr)))
            self.node_list.update({nid:l[1:]})
            node.bind(property_changed=self.on_node_property_changed)
        
    def on_new_node(self, **kwargs):
        node = kwargs.get('node')
        self.update_node_list()
        
    def on_del_node(self, **kwargs):
        node = kwargs.get('node')
        node.unbind(self)
        #self.update_node_list()
        self.node_list.delete_item(node.id)
    def on_node_property_changed(self, **kwargs):
        node = kwargs.get('obj')
        self.update_node_list(node.id)
        
class MidiSetup(EditorBase):
    topwidget_label = 'MIDI Setup'
    def init_editor(self, **kwargs):
        self.notebook = widgets.Notebook()
        dev_ed = self.make_child_editor(MidiDeviceEditor, 'device_editor')
        self.notebook.add_page(widget=dev_ed.topwidget, label='Devices')
        map_ed = self.make_child_editor(MidiMapEditor, 'map_editor')
        self.notebook.add_page(widget=map_ed.topwidget, label='Mapping')
        self.topwidget.pack_start(self.notebook, expand=True)

class MidiDeviceEditor(EditorBase):
    topwidget_label = 'Devices'
    def init_editor(self, **kwargs):
        self.midi_io = self.MainController.comm.midi_io
        self.models = {}
        self.trees = {}
        hbox = widgets.HBox()
        for key in ['in', 'out']:
            cg = self.midi_io.dev_info[key]
            model = PropertyListModel(child_group=cg)
            w = widgets.TreeView(name=cg.name)
            model.add_treeview(treeview=w)
            self.models[cg.name] = model
            self.trees[cg.name] = w
            hbox.pack_start(w.topwidget, expand=True)
        self.topwidget.pack_start(hbox, expand=True)
    def unlink(self):
        for model in self.models.itervalues():
            model.unlink()
        super(MidiDeviceEditor, self).unlink()
        
class MidiMapEditor(EditorBase):
    topwidget_label = 'Mapping'
    def init_editor(self, **kwargs):
        self.mapper = self.MainController.comm.midi_io.Mapper
        hbox = widgets.HBox()
        for mtype in self.mapper.map_types:
            ed = self.make_child_editor(MappingTree, '_'.join([mtype, 'editor']), map_type=mtype)
            hbox.pack_start(ed.topwidget, expand=True)
        self.topwidget.pack_start(hbox, expand=True)
        self.preset_list = widgets.TreeList(name='Automap Presets', 
                                            column_names=['Name', 'Description'], 
                                            column_order=[0, 1])
        for cls in self.mapper.automap_presets.itervalues():
            self.preset_list.update({cls.name:cls.description})
        #if self.mapper.AutoMapper is not None:
        #    self.preset_list.set_current_selection(key=self.mapper.AutoMapper.name)
        hbox = widgets.HBox()
        btn = widgets.Button(label='Apply')
        btn.connect('clicked', self.on_btnApply_clicked)
        hbox.pack_start(btn)
        btn = widgets.Button(label='Clear')
        btn.connect('clicked', self.on_btnClear_clicked)
        hbox.pack_start(btn)
        self.preset_list.topwidget.pack_start(hbox)
        self.topwidget.pack_start(self.preset_list.topwidget, expand=True)
        
    
        
    def on_btnApply_clicked(self, *args):
        key = self.preset_list.current_selection
        if key is None:
            return
        self.mapper.add_AutoMapper(key)
        
    def on_btnClear_clicked(self, *args):
        key = self.preset_list.current_selection
        if key is None:
            return
        self.mapper.del_AutoMapper(key)
        
    
            
class MappingTree(EditorBase):
    def init_editor(self, **kwargs):
        self.mapper = self.MainController.comm.midi_io.Mapper
        self.map_type = kwargs.get('map_type')
        self.map_treeview = widgets.TreeView(name=self.map_type)
        hbox = widgets.HBox()
        btn = widgets.Button(label='Add')
        btn.connect('clicked', self.on_btnAddMap_clicked)
        hbox.pack_start(btn)
        btn = widgets.Button(label='Delete')
        btn.connect('clicked', self.on_btnDelMap_clicked)
        hbox.pack_start(btn)
        self.map_treeview.topwidget.pack_start(hbox)
        self.map_model = None
        self.build_map_model()
        self.mapper.Map.bind(child_update=self.on_Map_child_update)
        self.topwidget.pack_start(self.map_treeview.topwidget, expand=True)
        
    def unlink(self):
        if self.map_model is not None:
            self.map_model.unlink()
        super(MappingTree, self).unlink()
        
    def build_map_model(self, **kwargs):
        if self.map_model is not None:
            return
        mmkwargs = dict(child_group=self.mapper.Map)
        child = kwargs.get('child')
        cls = None
        if child is None:
            for mp in self.mapper.Map.itervalues():
                if mp.map_type == self.map_type:
                    cls = mp.__class__
                    break
        elif 'child' in kwargs:
            cls = kwargs['child'].__class__
        if cls is None:
            return
        mmkwargs['used_classes'] = [cls]
        self.map_model = PropertyListModel(**mmkwargs)
        self.map_model.add_treeview(treeview=self.map_treeview, hidden_props=['id'])
        
    def on_btnAddMap_clicked(self, *args):
        map = self.mapper.add_map(type=self.map_type)
        self.map_treeview.selected = map.id
        
    def on_btnDelMap_clicked(self, *args):
        if self.map_treeview.selected is None:
            return
        self.mapper.del_map(id=self.map_treeview.selected)
        
    def on_Map_child_update(self, **kwargs):
        if kwargs.get('mode') == 'add':
            child = kwargs.get('obj')
            if child.map_type != self.map_type:
                return
            self.build_map_model(child=child)
            self.mapper.Map.unbind(self.on_Map_child_update)
    
UI_VIEW = CommSetupView
